import React, { useState, useEffect } from 'react';
import { Box, Typography, TextField, Button, FormControl, InputLabel, Select, MenuItem, FormHelperText, Paper, CircularProgress, Table, TableHead, TableBody, TableCell, TableRow, TableContainer, Alert, Checkbox, ListItemText, Dialog, DialogTitle, DialogContent, DialogActions, IconButton } from '@mui/material';
import DeleteIcon from '@mui/icons-material/Delete';
import AddIcon from '@mui/icons-material/Add';
import RefreshIcon from '@mui/icons-material/Refresh';
import { useParams } from 'react-router-dom';

// 依赖类型定义
export interface NodeParams {
  cleaning_type?: string;
  columns?: string | string[];
  threshold?: number;
  strategy?: string;
  fill_value?: string;
  method?: string;
  with_mean?: string;
  with_std?: string;
  feature_range?: string;
  quantile_range?: string;
  file?: File;
  filename?: string;
  processedData?: any[];
  separator?: string;
  encoding?: string;
  outlier_method?: string;
  z_score_threshold?: number;
  iqr_multiplier?: number;
  duplicate_strategy?: string;
  format_rules?: string;
  max_rows?: number;
  page_size?: number;
  filePath?: string;
  source_node?: string;
  row_count?: number;
  column_count?: number;
  target_column?: string;
  feature_columns?: string[];
  sheet_name?: string;
  [key: string]: any;
}

export interface NodeData extends Record<string, unknown> {
  type: string;
  label?: string;
  params?: {
    file?: File;
    filePath?: string;
    columns?: string[];
    processedData?: any[];
    target_column?: string;
    feature_columns?: string[];
    sheet_name?: string;
    [key: string]: unknown;
  };
  lastExecutionResult?: {
    metrics?: {
      accuracy: number;
      precision: number;
      recall: number;
      f1: number;
      confusion_matrix: number[][];
    };
    feature_importance?: Record<string, number>;
    training_info?: {
      n_features: number;
      n_samples_train: number;
      n_samples_test: number;
      classes: any[];
      model_type: string;
      feature_names?: string[];
    };
    columns?: string[];
    data?: any[];
    stats?: Record<string, any>;
    sheet_name?: string;
    available_sheets?: string[];
  };
}

export interface CustomNode {
  id: string;
  data: NodeData;
}

// 定义 PropertiesPanelProps 类型，添加 getUpstreamData 函数
interface PropertiesPanelProps {
    node: CustomNode;
    onUpdate: (nodeId: string, data: any) => void;
    onDelete: (nodeId: string) => void;
    onExecute: (nodeId: string) => Promise<void>;
    getUpstreamData: () => { columns: string[] };
}

const PropertiesPanel: React.FC<PropertiesPanelProps> = ({ node, onUpdate, onDelete, onExecute, getUpstreamData }) => {
    const [params, setParams] = useState<NodeParams>(node.data.params || {});
    const [label, setLabel] = useState(node.data.label);
    const [success, setSuccess] = useState<string | null>(null);
    const [error, setError] = useState<string | null>(null);
    const [isLoading, setIsLoading] = useState(false);
    const { id } = useParams<{ id: string }>();
    const [isColumnDialogOpen, setIsColumnDialogOpen] = useState(false);
    const [currentColumnType, setCurrentColumnType] = useState<'target' | 'feature'>('target');
    const [tempColumnValue, setTempColumnValue] = useState('');
    const [excelSheets, setExcelSheets] = useState<string[]>([]);
    const [isLoadingSheets, setIsLoadingSheets] = useState(false);

    useEffect(() => {
      setParams(node.data.params || {});
      setLabel(node.data.label || '');
      setSuccess(null);
      setError(null);
      setIsLoading(false);
    }, [node.data, node.id]);

    // 加载Excel工作表列表
    const loadExcelSheets = async (filePath: string) => {
      if (!filePath || !filePath.toLowerCase().endsWith('.xlsx') && !filePath.toLowerCase().endsWith('.xls')) {
        return;
      }
      
      // 首先检查节点的lastExecutionResult中是否有工作表列表
      if (node.data.lastExecutionResult?.available_sheets && 
          node.data.lastExecutionResult.available_sheets.length > 0) {
        console.log('从节点执行结果中获取工作表列表:', node.data.lastExecutionResult.available_sheets);
        setExcelSheets(node.data.lastExecutionResult.available_sheets);
        
        // 如果工作表名称已设置，确保它在下拉列表中被选中
        if (node.data.params?.sheet_name) {
          console.log('当前选择的工作表:', node.data.params.sheet_name);
          if (!params.sheet_name) {
            handleParamChange('sheet_name', node.data.params.sheet_name);
          }
        } else if (node.data.lastExecutionResult.sheet_name) {
          console.log('从执行结果中获取当前工作表:', node.data.lastExecutionResult.sheet_name);
          handleParamChange('sheet_name', node.data.lastExecutionResult.sheet_name);
        }
        return;
      }
      
      try {
        setIsLoadingSheets(true);
        setError(null);
        
        const response = await fetch(`/api/excel_sheets?file_path=${encodeURIComponent(filePath)}`);
        
        if (!response.ok) {
          throw new Error('获取工作表列表失败');
        }
        
        const data = await response.json();
        
        if (data.sheet_names && Array.isArray(data.sheet_names)) {
          setExcelSheets(data.sheet_names);
          console.log('获取到Excel工作表列表:', data.sheet_names);
          
          // 如果没有选择工作表，默认选择第一个
          if (!params.sheet_name && data.sheet_names.length > 0) {
            handleParamChange('sheet_name', data.sheet_names[0]);
          }
        } else {
          setExcelSheets([]);
        }
      } catch (err) {
        console.error('获取Excel工作表列表错误:', err);
        setError('获取工作表列表失败: ' + (err instanceof Error ? err.message : String(err)));
      } finally {
        setIsLoadingSheets(false);
      }
    };
    
    // 当文件路径改变时加载工作表列表
    useEffect(() => {
      if (node.data.type === 'excel_reader' && node.data.params?.filePath) {
        loadExcelSheets(node.data.params.filePath);
      }
    }, [node.data.params?.filePath, node.data.type]);

    const handleParamChange = (key: string, value: unknown) => {
      setParams(prevParams => ({
        ...prevParams,
        [key]: value
      }));
      onUpdate(node.id, {
        params: {
          ...(node.data.params || {}),
          [key]: value
        }
      });
      if (node.data.type === 'structured_view' && key === 'page_size') {
        console.log(`修改每页行数: ${value}，节点ID: ${node.id}`);
      }
    };

    const handleLabelChange = (value: string) => {
      setLabel(value);
      onUpdate(node.id, {
        label: value
      });
    };

    const handleFileChange = async (event: React.ChangeEvent<HTMLInputElement>) => {
      const file = event.target.files?.[0];
      if (!file) return;
      try {
        setIsLoading(true);
        setError(null);
        setSuccess(null);
        const formData = new FormData();
        formData.append('file', file);
        
        // 如果是Excel文件并且已选择工作表名称，则传递工作表名称
        if (file.name.endsWith('.xlsx') || file.name.endsWith('.xls')) {
          const sheetName = params.sheet_name;
          if (sheetName) {
            formData.append('sheet_name', sheetName);
          }
        }
        
        console.log('开始上传文件:', file.name);
        const response = await fetch('/api/upload', {
          method: 'POST',
          body: formData,
        });
        
        // 获取响应文本，无论成功与否
        const responseText = await response.text();
        let errorDetail = '';
        let errorMessage = '';
        
        // 尝试解析为JSON
        let data;
        try {
          data = JSON.parse(responseText);
        } catch (e) {
          // 如果无法解析为JSON，使用原始响应文本
          errorDetail = responseText;
        }
        
        if (!response.ok) {
          // 如果响应是JSON并且包含详细信息，则使用该信息
          if (data && data.detail) {
            errorDetail = data.detail;
            // 处理常见的技术错误，转换为用户友好的消息
            if (errorDetail.includes('Timestamp')) {
              errorMessage = '文件包含不支持的日期时间格式，请检查数据格式。';
            } else if (errorDetail.includes('NaTType')) {
              errorMessage = '文件包含无效的日期时间值，请检查日期字段。';
            } else if (errorDetail.includes('truth value of an array')) {
              errorMessage = '文件包含复杂的数据格式，系统无法正确处理。请简化数据。';
            } else if (errorDetail.includes('not JSON serializable')) {
              errorMessage = '文件包含无法处理的特殊数据类型，请检查并转换数据格式。';
            } else {
              // 提取技术错误消息的关键部分
              errorMessage = `上传失败: ${errorDetail.split(':').pop() || '未知错误'}`;
            }
          } else {
            errorMessage = '文件上传失败，请重试。';
          }
          throw new Error(errorMessage);
        }
        
        // 确保我们有数据对象
        if (!data) {
          throw new Error('服务器返回的数据格式无效');
        }
        
        // 检查是否有错误信息但仍然部分成功
        if (data.error) {
          console.warn('文件上传部分成功，但有错误:', data.error);
          setSuccess(`文件已上传，但处理过程中遇到问题: ${data.error.split(':').pop() || '未知问题'}`);
        } else {
          console.log('文件上传成功:', data);
          setSuccess(data.is_preview ? '文件选择成功（数据量较大，仅加载部分预览）' : '文件选择成功');
        }
        
        if (!data.file_path) {
          throw new Error('服务器未返回文件路径');
        }
        
        // 保存文件信息和工作表信息
        const newParams = {
          ...params,
          file,
          filename: file.name,
          filePath: data.file_path
        };
        
        // 如果是Excel文件，保存工作表信息
        if ((file.name.endsWith('.xlsx') || file.name.endsWith('.xls')) && 
            data.available_sheets && data.sheet_name) {
          console.log('保存Excel工作表信息:', data.sheet_name, data.available_sheets);
          newParams.sheet_name = data.sheet_name;
          
          // 更新工作表下拉列表
          setExcelSheets(data.available_sheets);
        }
        
        setParams(newParams);
        
        onUpdate(node.id, {
          ...node.data,
          params: {
            ...node.data.params,
            file,
            filename: file.name,
            filePath: data.file_path,
            // 如果是Excel文件，保存工作表信息
            ...(data.sheet_name ? { sheet_name: data.sheet_name } : {})
          },
          // 保存上传结果中的数据和工作表信息到lastExecutionResult中
          lastExecutionResult: {
            ...node.data.lastExecutionResult,
            data: data.data,
            columns: data.columns,
            ...(data.sheet_name ? { 
              sheet_name: data.sheet_name,
              available_sheets: data.available_sheets 
            } : {})
          }
        });
        setError(null);
      } catch (err) {
        console.error('文件上传错误:', err);
        setError((err instanceof Error ? err.message : String(err)) || '上传过程中发生未知错误');
        setSuccess(null);
      } finally {
        setIsLoading(false);
      }
    };

    const handleExecute = async () => {
      if (!node) return;
      
      try {
        setIsLoading(true);
        setError(null);
        setSuccess(null);

        // 检查是否是数据读取节点
        if (node.data.type === 'csv_reader' || node.data.type === 'excel_reader') {
          if (!node.data.params?.file) {
            setError('请先选择文件');
            setIsLoading(false);
            return;
          }
        }
        
        // 获取上游节点数据
        const upstreamData = getUpstreamData();
        console.log('上游数据:', upstreamData);
        
        // 如果是机器学习节点，检查是否有上游数据
        if (['logistic_regression', 'random_forest', 'svm'].includes(node.data.type)) {
          if (!upstreamData || !upstreamData.columns || upstreamData.columns.length === 0) {
            setError('没有可用于训练的数据，请确保上游数据源节点已执行');
            setIsLoading(false);
            return;
          }
        }
        
        // 直接调用WorkflowEditor中的执行函数
        console.log("调用全局执行函数 onExecute");
        try {
          const result = await onExecute(node.id);
          console.log('执行结果:', result);
          
          setSuccess('节点执行成功');
          setTimeout(() => setSuccess(''), 3000);
        } catch (err) {
          console.error('执行错误:', err);
          setError(err instanceof Error ? err.message : '执行失败');
        }
      } finally {
        setIsLoading(false);
      }
    };

    // 处理打开列选择对话框
    const handleOpenColumnDialog = (type: 'target' | 'feature') => {
      try {
        console.log('打开列选择对话框，类型:', type);
        console.log('当前节点类型:', node.data.type);
        
        // 获取上游数据
        const upstreamData = getUpstreamData();
        console.log('获取到的上游数据:', upstreamData);
        
        if (!upstreamData || !upstreamData.columns || upstreamData.columns.length === 0) {
          console.error('没有可用的上游数据列，请确保上游节点已执行');
          setError('没有可用的上游数据列，请确保上游节点已执行');
          return;
        }
        
        setCurrentColumnType(type);
        console.log('已设置currentColumnType:', type);
        
        // 从节点数据中获取当前值
        let currentValue = '';
        
        if (node.data.type === 'data_standardization' || node.data.type === 'one_hot_encoding') {
          // 数据标准化和OneHot编码节点特殊处理
          console.log(`${node.data.type}节点特殊处理列选择`);
          const columns = node.data.params?.columns;
          if (Array.isArray(columns)) {
            currentValue = columns.join(', ');
          } else if (typeof columns === 'string') {
            currentValue = columns;
          }
          console.log(`${node.data.type}节点当前选择的列:`, currentValue);
        } else {
          // 常规机器学习节点处理
          currentValue = type === 'target' 
            ? (node.data.params?.target_column || '')
            : (Array.isArray(node.data.params?.feature_columns) 
                ? node.data.params.feature_columns.join(', ')
                : '');
        }
        
        setTempColumnValue(currentValue);
        console.log('已设置tempColumnValue:', currentValue);
        
        // 设置对话框为打开状态
        setIsColumnDialogOpen(true);
        console.log('已设置isColumnDialogOpen为true');
      } catch (err) {
        console.error('打开列选择对话框时出错:', err);
        setError('打开列选择对话框时出错: ' + (err instanceof Error ? err.message : String(err)));
      }
    };

    // 处理关闭列选择对话框
    const handleCloseColumnDialog = () => {
      setIsColumnDialogOpen(false);
    };

    // 处理确认列选择
    const handleConfirmColumnSelection = () => {
      console.log('确认列选择，当前节点类型:', node.data.type);
      console.log('选择的列值:', tempColumnValue);
      
      if (node.data.type === 'data_standardization' || node.data.type === 'one_hot_encoding') {
        // 数据标准化和OneHot编码节点特殊处理
        const columnsArray = tempColumnValue.split(',').map(col => col.trim()).filter(Boolean);
        console.log(`${node.data.type} 节点 - 处理列数组:`, columnsArray);
        handleParamChange('columns', columnsArray);
      } else if (currentColumnType === 'target') {
        // 更新目标列
        handleParamChange('target_column', tempColumnValue);
      } else {
        // 更新特征列
        const featureColumns = tempColumnValue.split(',').map(col => col.trim()).filter(Boolean);
        handleParamChange('feature_columns', featureColumns);
      }
      
      setIsColumnDialogOpen(false);
    };

    // 渲染列选择对话框
    const renderColumnSelectionDialog = () => {
      console.log('渲染列选择对话框');
      const upstreamData = getUpstreamData();
      const availableColumns = upstreamData.columns || [];
      
      console.log('列选择对话框 - 可用列:', availableColumns);
      console.log('当前列类型:', currentColumnType);
      console.log('临时列值:', tempColumnValue);
      
      const dialogTitle = node.data.type === 'data_standardization' ? 
        '选择处理列' : 
        (currentColumnType === 'target' ? '选择目标列' : '选择特征列');
      
      return (
        <Dialog 
          open={isColumnDialogOpen} 
          onClose={handleCloseColumnDialog}
          maxWidth="sm"
          fullWidth
        >
          <DialogTitle>
            {dialogTitle}
          </DialogTitle>
          <DialogContent>
            <Box sx={{ mt: 2 }}>
              <Typography variant="subtitle2" gutterBottom>
                可用字段：
              </Typography>
              <Box sx={{ maxHeight: 300, overflow: 'auto', mb: 2 }}>
                {availableColumns.length === 0 ? (
                  <Typography color="text.secondary">
                    没有可用的字段，请确保上游节点已正确执行
                  </Typography>
                ) : (
                  availableColumns.map((column) => {
                    const tempColumns = tempColumnValue.split(',').map(col => col.trim());
                    const isSelected = currentColumnType === 'target'
                      ? tempColumnValue === column
                      : tempColumns.includes(column);
                    
                    return (
                      <Box key={column} sx={{ display: 'flex', alignItems: 'center', py: 0.5 }}>
                        <Checkbox
                          checked={isSelected}
                          onChange={() => {
                            if (currentColumnType === 'target' && node.data.type !== 'data_standardization') {
                              setTempColumnValue(column);
                            } else {
                              const currentColumns = tempColumnValue ? tempColumnValue.split(',').map(col => col.trim()) : [];
                              if (isSelected) {
                                setTempColumnValue(currentColumns.filter(col => col !== column).join(', '));
                              } else {
                                setTempColumnValue([...currentColumns, column].join(', '));
                              }
                            }
                          }}
                        />
                        <Typography>{column}</Typography>
                      </Box>
                    );
                  })
                )}
              </Box>
            </Box>
          </DialogContent>
          <DialogActions>
            <Button onClick={handleCloseColumnDialog}>取消</Button>
            <Button onClick={handleConfirmColumnSelection} variant="contained">
              确认
            </Button>
          </DialogActions>
        </Dialog>
      );
    };

    // 渲染数据输入节点参数
    const renderDataInputParams = () => {
      if (!['csv_reader', 'excel_reader', 'db_reader'].includes(node.data.type)) {
        return null;
      }

      return (
        <Box sx={{ mt: 2 }}>
          <Typography variant="subtitle2" gutterBottom>
            文件设置
          </Typography>
          <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
            <Button
              variant="outlined"
              component="label"
              fullWidth
              disabled={isLoading}
              startIcon={isLoading ? <CircularProgress size={16} /> : null}
            >
              {isLoading ? '上传中...' : '选择文件'}
              <input
                type="file"
                hidden
                accept={
                  node.data.type === 'csv_reader' ? '.csv' :
                  node.data.type === 'excel_reader' ? '.xlsx,.xls' :
                  '*'
                }
                onChange={handleFileChange}
                disabled={isLoading}
              />
            </Button>
            {isLoading && (
              <Box sx={{ mt: 1, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                <Typography variant="caption" color="text.secondary" sx={{ ml: 1 }}>
                  正在处理文件，请稍候...
                </Typography>
              </Box>
            )}
            {params.filename && (
              <Typography variant="body2" color="text.secondary">
                已选择: {params.filename}
              </Typography>
            )}
            
            {/* Excel工作表选择 */}
            {node.data.type === 'excel_reader' && params.filePath && (
              <Box sx={{ mt: 1 }}>
                <FormControl fullWidth size="small">
                  <InputLabel>工作表</InputLabel>
                  <Select
                    value={params.sheet_name || ''}
                    label="工作表"
                    onChange={(e) => {
                      const newSheetName = e.target.value as string;
                      handleParamChange('sheet_name', newSheetName);
                      
                      // 如果更改了工作表，自动重新上传文件以加载该表
                      if (params.file && newSheetName) {
                        const formData = new FormData();
                        formData.append('file', params.file);
                        formData.append('sheet_name', newSheetName);
                        
                        setIsLoading(true);
                        fetch('/api/upload', {
                          method: 'POST',
                          body: formData,
                        })
                        .then(response => response.json())
                        .then(data => {
                          console.log('工作表切换，重新加载数据:', data);
                          
                          // 更新节点数据
                          onUpdate(node.id, {
                            ...node.data,
                            params: {
                              ...node.data.params,
                              sheet_name: newSheetName,
                            },
                            // 保存上传结果中的工作表信息到lastExecutionResult中
                            lastExecutionResult: {
                              ...node.data.lastExecutionResult,
                              data: data.data,
                              columns: data.columns,
                              sheet_name: data.sheet_name,
                              available_sheets: data.available_sheets
                            }
                          });
                          
                          setSuccess(`已切换到工作表: ${newSheetName}`);
                          
                          // 执行节点，通知下游节点数据已更新
                          onExecute(node.id)
                            .then(() => {
                              console.log('节点已执行，下游节点将收到更新的数据');
                            })
                            .catch(err => {
                              console.error('执行节点失败:', err);
                            });
                        })
                        .catch(err => {
                          console.error('工作表切换失败:', err);
                          setError('工作表切换失败: ' + err.message);
                        })
                        .finally(() => setIsLoading(false));
                      }
                    }}
                    endAdornment={
                      <IconButton 
                        size="small"
                        sx={{ mr: 2 }}
                        onClick={() => params.filePath && loadExcelSheets(params.filePath)}
                        disabled={isLoadingSheets}
                      >
                        {isLoadingSheets ? <CircularProgress size={16} /> : <RefreshIcon fontSize="small" />}
                      </IconButton>
                    }
                    disabled={isLoadingSheets || excelSheets.length === 0}
                  >
                    {excelSheets.length === 0 ? (
                      <MenuItem disabled value="">无可用工作表</MenuItem>
                    ) : (
                      excelSheets.map(sheet => (
                        <MenuItem key={sheet} value={sheet}>{sheet}</MenuItem>
                      ))
                    )}
                  </Select>
                  <FormHelperText>
                    {isLoadingSheets ? '加载工作表列表...' : 
                     excelSheets.length === 0 ? '点击刷新按钮加载工作表' : 
                     `共${excelSheets.length}个工作表，当前选择: ${params.sheet_name || '默认'}`}
                  </FormHelperText>
                </FormControl>
              </Box>
            )}
            
            {node.data.type === 'csv_reader' && (
              <>
                <TextField
                  label="分隔符"
                  value={params.separator || ','}
                  onChange={(e) => handleParamChange('separator', e.target.value)}
                  size="small"
                  fullWidth
                />
                <TextField
                  label="编码"
                  value={params.encoding || 'utf-8'}
                  onChange={(e) => handleParamChange('encoding', e.target.value)}
                  size="small"
                  fullWidth
                />
              </>
            )}
          </Box>
        </Box>
      );
    };

    // 渲染数据处理节点参数
    const renderDataProcessingParams = () => {
      if (!['data_cleaning', 'data_standardization', 'outlier_detection', 'one_hot_encoding'].includes(node.data.type)) {
        return null;
      }

      return (
        <Box sx={{ mt: 2 }}>
          <Typography variant="subtitle2" gutterBottom>
            处理设置
          </Typography>
          <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
            {/* 只为非数据标准化节点显示简单的处理列输入框 */}
            {node.data.type !== 'data_standardization' && node.data.type !== 'one_hot_encoding' && (
              <TextField
                label="处理列"
                value={params.columns || ''}
                onChange={(e) => handleParamChange('columns', e.target.value)}
                size="small"
                fullWidth
                helperText="输入要处理的列名，多个列用逗号分隔"
              />
            )}
            
            {node.data.type === 'one_hot_encoding' && (
              <>
                {/* OneHot编码列选择 */}
                <Box sx={{ mt: 2, mb: 2 }}>
                  <Typography variant="subtitle2" gutterBottom>
                    分类列选择
                  </Typography>
                  <TextField
                    fullWidth
                    label="要编码的列"
                    value={Array.isArray(params.columns) ? params.columns.join(', ') : params.columns || ''}
                    onChange={(e) => {
                      // 拆分字符串为数组
                      const columnsArray = e.target.value.split(',').map(col => col.trim()).filter(Boolean);
                      handleParamChange('columns', columnsArray);
                    }}
                    InputProps={{
                      endAdornment: (
                        <IconButton 
                          onClick={() => {
                            console.log('OneHot编码节点 - 点击添加列按钮');
                            
                            // 先确保对话框关闭
                            setIsColumnDialogOpen(false);
                            
                            // 然后使用setTimeout延迟打开，确保状态更新
                            setTimeout(() => {
                              // 获取上游数据
                              const upstreamData = getUpstreamData();
                              console.log('OneHot编码节点 - 上游数据:', upstreamData);
                              
                              // 直接使用handleOpenColumnDialog函数
                              handleOpenColumnDialog('feature');
                              console.log('对话框打开状态已设置为true');
                            }, 100);
                          }}
                          size="small"
                        >
                          <AddIcon />
                        </IconButton>
                      ),
                    }}
                    multiline
                    rows={2}
                  />
                  <FormHelperText>
                    输入要进行OneHot编码的分类列（用逗号分隔），或点击按钮从列表中选择
                  </FormHelperText>
                </Box>

                <FormControl fullWidth size="small">
                  <InputLabel>添加前缀</InputLabel>
                  <Select
                    value={params.use_prefix === undefined ? 'true' : params.use_prefix}
                    label="添加前缀"
                    onChange={(e) => handleParamChange('use_prefix', e.target.value)}
                  >
                    <MenuItem value="true">是</MenuItem>
                    <MenuItem value="false">否</MenuItem>
                  </Select>
                  <FormHelperText>是否在编码后的列名前添加原列名作为前缀</FormHelperText>
                </FormControl>

                <TextField
                  label="最大类别数"
                  type="number"
                  value={params.max_categories || 20}
                  onChange={(e) => handleParamChange('max_categories', e.target.value)}
                  size="small"
                  fullWidth
                  helperText="单列中类别数量超过此值时跳过编码，避免生成过多稀疏列"
                />

                {/* 显示选择的列数信息 */}
                {Array.isArray(params.columns) && params.columns.length > 0 && (
                  <Box sx={{ mt: 2, p: 1, bgcolor: '#f5f5f5', borderRadius: 1 }}>
                    <Typography variant="caption" color="text.secondary">
                      已选择 {params.columns.length} 个列进行OneHot编码
                    </Typography>
                  </Box>
                )}

                {/* 显示OneHot编码结果预览 */}
                {node.data.lastExecutionResult?.data && (
                  <Box sx={{ mt: 2 }}>
                    <Typography variant="subtitle2" gutterBottom>
                      编码结果预览
                    </Typography>
                    <Typography variant="body2" color="text.secondary">
                      原始数据列数: {Array.isArray(node.data.lastExecutionResult.columns) ? node.data.lastExecutionResult.columns.length : 0} 列
                    </Typography>
                    
                    {/* 添加数据预览 */}
                    <Paper variant="outlined" sx={{ p: 1, mt: 1, maxHeight: 150, overflow: 'auto' }}>
                      <TableContainer>
                        <Table size="small">
                          <TableHead>
                            <TableRow>
                              {node.data.lastExecutionResult.columns?.slice(0, 7).map((col: string) => (
                                <TableCell key={col}>{col}</TableCell>
                              ))}
                              {(node.data.lastExecutionResult.columns?.length || 0) > 7 && (
                                <TableCell>...</TableCell>
                              )}
                            </TableRow>
                          </TableHead>
                          <TableBody>
                            {node.data.lastExecutionResult.data?.slice(0, 3).map((row: any, index: number) => (
                              <TableRow key={index}>
                                {node.data.lastExecutionResult?.columns?.slice(0, 7).map((col: string) => (
                                  <TableCell key={col}>{row[col]}</TableCell>
                                ))}
                                {(node.data.lastExecutionResult?.columns?.length || 0) > 7 && (
                                  <TableCell>...</TableCell>
                                )}
                              </TableRow>
                            ))}
                          </TableBody>
                        </Table>
                      </TableContainer>
                    </Paper>
                    <Typography variant="caption" color="text.secondary" sx={{ mt: 1, display: 'block' }}>
                      OneHot编码列的值为0或1，表示该类别是否存在
                    </Typography>
                  </Box>
                )}
              </>
            )}
            
            {node.data.type === 'data_cleaning' && (
              <>
                <FormControl size="small" fullWidth>
                  <InputLabel>清洗类型</InputLabel>
                  <Select
                    value={params.cleaning_type || 'missing'}
                    label="清洗类型"
                    onChange={(e) => handleParamChange('cleaning_type', e.target.value)}
                  >
                    <MenuItem value="missing">缺失值处理</MenuItem>
                    <MenuItem value="duplicate">重复值处理</MenuItem>
                    <MenuItem value="format">格式转换</MenuItem>
                  </Select>
                </FormControl>
                {params.cleaning_type === 'missing' && (
                  <TextField
                    label="填充值"
                    value={params.fill_value || ''}
                    onChange={(e) => handleParamChange('fill_value', e.target.value)}
                    size="small"
                    fullWidth
                  />
                )}
              </>
            )}

            {node.data.type === 'data_standardization' && (
              <>
                <FormControl size="small" fullWidth>
                  <InputLabel>标准化方法</InputLabel>
                  <Select
                    value={params.method || 'zscore'}
                    label="标准化方法"
                    onChange={(e) => handleParamChange('method', e.target.value)}
                  >
                    <MenuItem value="zscore">Z-Score标准化</MenuItem>
                    <MenuItem value="minmax">Min-Max标准化</MenuItem>
                    <MenuItem value="robust">Robust标准化</MenuItem>
                  </Select>
                  <FormHelperText>
                    {params.method === 'zscore' ? 
                      'Z-Score标准化将数据转换为均值为0，标准差为1的分布' : 
                      params.method === 'minmax' ? 
                      'Min-Max标准化将数据缩放到指定的范围内' :
                      'Robust标准化使用中位数和四分位距，对异常值不敏感'}
                  </FormHelperText>
                </FormControl>

                {/* 特征列选择 */}
                <Box sx={{ mt: 2, mb: 2 }}>
                  <Typography variant="subtitle2" gutterBottom>
                    特征列选择
                  </Typography>
                  <TextField
                    fullWidth
                    label="处理列"
                    value={Array.isArray(params.columns) ? params.columns.join(', ') : params.columns || ''}
                    onChange={(e) => {
                      // 拆分字符串为数组
                      const columnsArray = e.target.value.split(',').map(col => col.trim()).filter(Boolean);
                      handleParamChange('columns', columnsArray);
                    }}
                    InputProps={{
                      endAdornment: (
                        <IconButton 
                          onClick={() => {
                            console.log('数据标准化节点 - 点击添加列按钮');
                            
                            // 先确保对话框关闭
                            setIsColumnDialogOpen(false);
                            
                            // 然后使用setTimeout延迟打开，确保状态更新
                            setTimeout(() => {
                              // 获取上游数据
                              const upstreamData = getUpstreamData();
                              console.log('数据标准化节点 - 上游数据:', upstreamData);
                              
                              // 直接使用handleOpenColumnDialog函数
                              handleOpenColumnDialog('feature');
                              console.log('对话框打开状态已设置为true');
                            }, 100);
                          }}
                          size="small"
                        >
                          <AddIcon />
                        </IconButton>
                      ),
                    }}
                    multiline
                    rows={2}
                  />
                  <FormHelperText>
                    输入要处理的列名（用逗号分隔），或点击按钮从列表中选择
                  </FormHelperText>
                </Box>

                {/* 为每种方法添加具体参数 */}
                {params.method === 'zscore' && (
                  <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2, mt: 2 }}>
                    <FormControl fullWidth size="small">
                      <InputLabel>中心化</InputLabel>
                      <Select
                        value={params.with_mean === undefined ? 'true' : params.with_mean}
                        label="中心化"
                        onChange={(e) => handleParamChange('with_mean', e.target.value)}
                      >
                        <MenuItem value="true">是</MenuItem>
                        <MenuItem value="false">否</MenuItem>
                      </Select>
                      <FormHelperText>是否将数据转换为均值为0</FormHelperText>
                    </FormControl>
                    
                    <FormControl fullWidth size="small">
                      <InputLabel>缩放</InputLabel>
                      <Select
                        value={params.with_std === undefined ? 'true' : params.with_std}
                        label="缩放"
                        onChange={(e) => handleParamChange('with_std', e.target.value)}
                      >
                        <MenuItem value="true">是</MenuItem>
                        <MenuItem value="false">否</MenuItem>
                      </Select>
                      <FormHelperText>是否将数据缩放为标准差为1</FormHelperText>
                    </FormControl>
                  </Box>
                )}

                {params.method === 'minmax' && (
                  <Box sx={{ mt: 2 }}>
                    <TextField
                      label="特征范围"
                      value={params.feature_range || '0,1'}
                      onChange={(e) => handleParamChange('feature_range', e.target.value)}
                      size="small"
                      fullWidth
                      helperText="输入目标范围，格式为'最小值,最大值'，如'0,1'"
                    />
                  </Box>
                )}

                {params.method === 'robust' && (
                  <Box sx={{ mt: 2 }}>
                    <TextField
                      label="分位数范围"
                      value={params.quantile_range || '25.0,75.0'}
                      onChange={(e) => handleParamChange('quantile_range', e.target.value)}
                      size="small"
                      fullWidth
                      helperText="输入分位数范围，格式为'下限,上限'，如'25.0,75.0'"
                    />
                  </Box>
                )}

                {/* 确保渲染列选择对话框 */}
                {renderColumnSelectionDialog()}

                {/* 显示选择的列数信息 */}
                {Array.isArray(params.columns) && params.columns.length > 0 && (
                  <Box sx={{ mt: 2, p: 1, bgcolor: '#f5f5f5', borderRadius: 1 }}>
                    <Typography variant="caption" color="text.secondary">
                      已选择 {params.columns.length} 个列进行标准化处理
                    </Typography>
                  </Box>
                )}

                {/* 显示标准化结果预览 */}
                {node.data.lastExecutionResult?.data && (
                  <Box sx={{ mt: 2 }}>
                    <Typography variant="subtitle2" gutterBottom>
                      处理结果预览
                    </Typography>
                    
                    {/* 结果统计信息 */}
                    {node.data.lastExecutionResult.stats && (
                      <Box sx={{ mb: 2 }}>
                        <Typography variant="caption" gutterBottom>
                          数据统计信息:
                        </Typography>
                        <TableContainer component={Paper} variant="outlined" sx={{ mb: 1 }}>
                          <Table size="small">
                            <TableHead>
                              <TableRow>
                                <TableCell>列名</TableCell>
                                <TableCell>均值</TableCell>
                                <TableCell>标准差</TableCell>
                                <TableCell>最小值</TableCell>
                                <TableCell>最大值</TableCell>
                              </TableRow>
                            </TableHead>
                            <TableBody>
                              {Object.entries(node.data.lastExecutionResult.stats).slice(0, 3).map(([col, stats]: [string, any]) => (
                                <TableRow key={col}>
                                  <TableCell>{col}</TableCell>
                                  <TableCell>{stats.mean.toFixed(3)}</TableCell>
                                  <TableCell>{stats.std.toFixed(3)}</TableCell>
                                  <TableCell>{stats.min.toFixed(3)}</TableCell>
                                  <TableCell>{stats.max.toFixed(3)}</TableCell>
                                </TableRow>
                              ))}
                              {Object.keys(node.data.lastExecutionResult.stats).length > 3 && (
                                <TableRow>
                                  <TableCell colSpan={5} align="center">...</TableCell>
                                </TableRow>
                              )}
                            </TableBody>
                          </Table>
                        </TableContainer>
                        <Typography variant="caption" color="text.secondary">
                          标准化方法: {params.method === 'zscore' ? 'Z-Score标准化' : 
                                    params.method === 'minmax' ? 'Min-Max标准化' : 
                                    'Robust标准化'}
                        </Typography>
                      </Box>
                    )}
                    
                    {/* 数据预览 */}
                    <Paper variant="outlined" sx={{ p: 1, maxHeight: 120, overflow: 'auto' }}>
                      <TableContainer>
                        <Table size="small">
                          <TableHead>
                            <TableRow>
                              {node.data.lastExecutionResult.columns?.slice(0, 5).map((col: string) => (
                                <TableCell key={col}>{col}</TableCell>
                              ))}
                              {(node.data.lastExecutionResult.columns?.length || 0) > 5 && (
                                <TableCell>...</TableCell>
                              )}
                            </TableRow>
                          </TableHead>
                          <TableBody>
                            {node.data.lastExecutionResult.data?.slice(0, 3).map((row: any, index: number) => (
                              <TableRow key={index}>
                                {node.data.lastExecutionResult?.columns?.slice(0, 5).map((col: string) => (
                                  <TableCell key={col}>{typeof row[col] === 'number' ? row[col].toFixed(3) : row[col]}</TableCell>
                                ))}
                                {(node.data.lastExecutionResult?.columns?.length || 0) > 5 && (
                                  <TableCell>...</TableCell>
                                )}
                              </TableRow>
                            ))}
                            {(node.data.lastExecutionResult.data?.length || 0) > 3 && (
                              <TableRow>
                                <TableCell colSpan={(node.data.lastExecutionResult?.columns?.length || 0) > 5 ? 6 : node.data.lastExecutionResult?.columns?.length || 0}>
                                  ...
                                </TableCell>
                              </TableRow>
                            )}
                          </TableBody>
                        </Table>
                      </TableContainer>
                    </Paper>
                    <Typography variant="caption" color="text.secondary">
                      处理完成，共{node.data.lastExecutionResult.data?.length || 0}行数据
                    </Typography>
                  </Box>
                )}
              </>
            )}

            {node.data.type === 'outlier_detection' && (
              <>
                <FormControl size="small" fullWidth>
                  <InputLabel>检测方法</InputLabel>
                  <Select
                    value={params.outlier_method || 'zscore'}
                    label="检测方法"
                    onChange={(e) => handleParamChange('outlier_method', e.target.value)}
                  >
                    <MenuItem value="zscore">Z-Score法</MenuItem>
                    <MenuItem value="iqr">IQR法</MenuItem>
                  </Select>
                </FormControl>
                {params.outlier_method === 'zscore' && (
                  <TextField
                    label="Z-Score阈值"
                    type="number"
                    value={params.z_score_threshold || 3}
                    onChange={(e) => handleParamChange('z_score_threshold', Number(e.target.value))}
                    size="small"
                    fullWidth
                  />
                )}
                {params.outlier_method === 'iqr' && (
                  <TextField
                    label="IQR倍数"
                    type="number"
                    value={params.iqr_multiplier || 1.5}
                    onChange={(e) => handleParamChange('iqr_multiplier', Number(e.target.value))}
                    size="small"
                    fullWidth
                  />
                )}
              </>
            )}
          </Box>
        </Box>
      );
    };

    // 渲染机器学习节点参数
    const renderMachineLearningParams = () => {
      if (!['logistic_regression', 'random_forest', 'svm'].includes(node.data.type)) {
        return null;
      }

      // 渲染模型特定参数
      const renderModelSpecificParams = () => {
        if (node.data.type === 'logistic_regression') {
          return (
            <Box sx={{ mb: 2 }}>
              <Typography variant="subtitle2" gutterBottom>
                逻辑回归参数
              </Typography>
              
              <FormControl fullWidth size="small" sx={{ mb: 2 }}>
                <InputLabel>正则化类型</InputLabel>
                <Select
                  value={node.data.params?.penalty || 'l2'}
                  label="正则化类型"
                  onChange={(e) => handleParamChange('penalty', e.target.value)}
                >
                  <MenuItem value="l1">L1正则化</MenuItem>
                  <MenuItem value="l2">L2正则化</MenuItem>
                  <MenuItem value="elasticnet">弹性网络</MenuItem>
                  <MenuItem value="none">无正则化</MenuItem>
                </Select>
                <FormHelperText>
                  L1会产生稀疏解，L2适用于处理多重共线性
                </FormHelperText>
              </FormControl>
              
              <TextField
                fullWidth
                label="正则化强度 (C)"
                type="number"
                value={node.data.params?.C || 1.0}
                onChange={(e) => handleParamChange('C', parseFloat(e.target.value))}
                inputProps={{ min: 0.001, step: 0.1 }}
                sx={{ mb: 2 }}
                helperText="值越小，正则化越强。默认为1.0"
              />
              
              <TextField
                fullWidth
                label="最大迭代次数"
                type="number"
                value={node.data.params?.max_iter || 100}
                onChange={(e) => handleParamChange('max_iter', parseInt(e.target.value))}
                inputProps={{ min: 10, step: 10 }}
                sx={{ mb: 2 }}
                helperText="算法收敛的最大迭代次数"
              />
            </Box>
          );
        } else if (node.data.type === 'random_forest') {
          return (
            <Box sx={{ mb: 2 }}>
              <Typography variant="subtitle2" gutterBottom>
                随机森林参数
              </Typography>
              
              <TextField
                fullWidth
                label="树的数量"
                type="number"
                value={node.data.params?.n_estimators || 100}
                onChange={(e) => handleParamChange('n_estimators', parseInt(e.target.value))}
                inputProps={{ min: 10, step: 10 }}
                sx={{ mb: 2 }}
                helperText="森林中树的数量，通常越多越好，但也会增加计算复杂度"
              />
              
              <TextField
                fullWidth
                label="最大深度"
                type="number"
                value={node.data.params?.max_depth || ''}
                onChange={(e) => {
                  const value = e.target.value ? parseInt(e.target.value) : null;
                  handleParamChange('max_depth', value);
                }}
                inputProps={{ min: 1, step: 1 }}
                sx={{ mb: 2 }}
                helperText="树的最大深度，留空表示无限制"
              />
              
              <TextField
                fullWidth
                label="最小分裂样本数"
                type="number"
                value={node.data.params?.min_samples_split || 2}
                onChange={(e) => handleParamChange('min_samples_split', parseInt(e.target.value))}
                inputProps={{ min: 2, step: 1 }}
                sx={{ mb: 2 }}
                helperText="分裂内部节点所需的最小样本数"
              />
              
              <TextField
                fullWidth
                label="最小叶节点样本数"
                type="number"
                value={node.data.params?.min_samples_leaf || 1}
                onChange={(e) => handleParamChange('min_samples_leaf', parseInt(e.target.value))}
                inputProps={{ min: 1, step: 1 }}
                sx={{ mb: 2 }}
                helperText="叶节点所需的最小样本数，可以平滑模型"
              />
              
              <FormControl fullWidth size="small" sx={{ mb: 2 }}>
                <InputLabel>特征选择标准</InputLabel>
                <Select
                  value={node.data.params?.criterion || 'gini'}
                  label="特征选择标准"
                  onChange={(e) => handleParamChange('criterion', e.target.value)}
                >
                  <MenuItem value="gini">基尼不纯度</MenuItem>
                  <MenuItem value="entropy">信息熵</MenuItem>
                </Select>
                <FormHelperText>
                  衡量分裂质量的函数，两者通常表现相似
                </FormHelperText>
              </FormControl>
            </Box>
          );
        } else if (node.data.type === 'svm') {
          return (
            <Box sx={{ mb: 2 }}>
              <Typography variant="subtitle2" gutterBottom>
                SVM参数
              </Typography>
              
              <FormControl fullWidth size="small" sx={{ mb: 2 }}>
                <InputLabel>核函数</InputLabel>
                <Select
                  value={node.data.params?.kernel || 'rbf'}
                  label="核函数"
                  onChange={(e) => handleParamChange('kernel', e.target.value)}
                >
                  <MenuItem value="linear">线性核</MenuItem>
                  <MenuItem value="poly">多项式核</MenuItem>
                  <MenuItem value="rbf">径向基函数(RBF)</MenuItem>
                  <MenuItem value="sigmoid">Sigmoid核</MenuItem>
                </Select>
                <FormHelperText>
                  线性核适用于线性可分数据，RBF核适用于非线性数据
                </FormHelperText>
              </FormControl>
              
              <TextField
                fullWidth
                label="正则化参数 (C)"
                type="number"
                value={node.data.params?.C || 1.0}
                onChange={(e) => handleParamChange('C', parseFloat(e.target.value))}
                inputProps={{ min: 0.001, step: 0.1 }}
                sx={{ mb: 2 }}
                helperText="权衡错误分类的惩罚与决策边界的平滑度"
              />
              
              {(node.data.params?.kernel === 'rbf' || node.data.params?.kernel === 'poly' || node.data.params?.kernel === 'sigmoid') && (
                <TextField
                  fullWidth
                  label="Gamma"
                  type="number"
                  value={node.data.params?.gamma || 'scale'}
                  onChange={(e) => {
                    const value = !isNaN(parseFloat(e.target.value)) ? parseFloat(e.target.value) : e.target.value;
                    handleParamChange('gamma', value);
                  }}
                  sx={{ mb: 2 }}
                  helperText="核系数，可以是数值或'scale'/'auto'"
                />
              )}
              
              {node.data.params?.kernel === 'poly' && (
                <TextField
                  fullWidth
                  label="多项式次数"
                  type="number"
                  value={node.data.params?.degree || 3}
                  onChange={(e) => handleParamChange('degree', parseInt(e.target.value))}
                  inputProps={{ min: 1, step: 1 }}
                  sx={{ mb: 2 }}
                  helperText="多项式核函数的次数"
                />
              )}
            </Box>
          );
        }
        
        return null;
      };

      const renderModelParams = () => {
        if (node.data.type === 'model_evaluation') {
          return null;
        }
        
        return (
          <Box>
            {/* 目标列选择 */}
            <Box sx={{ mb: 2 }}>
              <TextField
                fullWidth
                label="目标列"
                value={node.data.params?.target_column || ''}
                onChange={(e) => handleParamChange('target_column', e.target.value)}
                InputProps={{
                  endAdornment: (
                    <IconButton onClick={() => handleOpenColumnDialog('target')}>
                      <AddIcon />
                    </IconButton>
                  ),
                }}
              />
              <FormHelperText>
                输入目标列名称，或点击按钮从列表中选择
              </FormHelperText>
            </Box>

            {/* 特征列选择 */}
            <Box sx={{ mb: 2 }}>
              <TextField
                fullWidth
                label="特征列"
                value={Array.isArray(node.data.params?.feature_columns) 
                  ? node.data.params.feature_columns.join(', ')
                  : ''}
                onChange={(e) => handleParamChange('feature_columns', e.target.value.split(',').map(col => col.trim()))}
                InputProps={{
                  endAdornment: (
                    <IconButton onClick={() => handleOpenColumnDialog('feature')}>
                      <AddIcon />
                    </IconButton>
                  ),
                }}
                multiline
                rows={2}
              />
              <FormHelperText>
                输入特征列名称（用逗号分隔），或点击按钮从列表中选择
              </FormHelperText>
            </Box>

            {/* 渲染模型特定参数 */}
            {renderModelSpecificParams()}

            {/* 其他机器学习通用参数 */}
            <Typography variant="subtitle2" gutterBottom>
              训练与评估
            </Typography>
            
            <TextField
              fullWidth
              label="测试集比例"
              type="number"
              value={node.data.params?.test_size || 0.2}
              onChange={(e) => handleParamChange('test_size', parseFloat(e.target.value))}
              inputProps={{ min: 0.1, max: 0.5, step: 0.05 }}
              sx={{ mb: 2 }}
              helperText="用于评估的数据比例，通常为0.2-0.3"
            />
            
            <TextField
              fullWidth
              label="随机种子"
              type="number"
              value={node.data.params?.random_state || 42}
              onChange={(e) => handleParamChange('random_state', parseInt(e.target.value))}
              sx={{ mb: 2 }}
              helperText="确保结果可重现的随机数种子"
            />
          </Box>
        );
      };

      return (
        <Box sx={{ mt: 2 }}>
          <Typography variant="subtitle2" gutterBottom>
            机器学习设置
          </Typography>
          
          {renderModelParams()}
          
          {/* 列选择对话框 */}
          {renderColumnSelectionDialog()}
        </Box>
      );
    };

    // 渲染可视化节点参数
    const renderVisualizationParams = () => {
      if (!['structured_view', 'bar_chart', 'line_chart', 'scatter_plot', 'pie_chart', 'heatmap', 'model_evaluation'].includes(node.data.type)) {
        return null;
      }

      // 模型评估节点参数渲染
      const renderModelEvaluationParams = () => {
        if (node.data.type !== 'model_evaluation') {
          return null;
        }

        // 添加调试输出
        console.log('PropertiesPanel - 模型评估节点属性:', node.data);
        console.log('PropertiesPanel - 模型评估节点执行结果:', node.data.lastExecutionResult);
        
        const metrics = node.data.lastExecutionResult?.metrics;
        console.log('PropertiesPanel - metrics:', metrics);
        
        const hasMetrics = metrics && 
                           typeof metrics.accuracy === 'number' && 
                           typeof metrics.precision === 'number' && 
                           typeof metrics.recall === 'number' && 
                           typeof metrics.f1 === 'number';
        
        console.log('PropertiesPanel - hasMetrics:', hasMetrics);
        if (metrics) {
          console.log('PropertiesPanel - metrics值类型:', {
            accuracy: typeof metrics.accuracy,
            precision: typeof metrics.precision,
            recall: typeof metrics.recall,
            f1: typeof metrics.f1
          });
        }

        return (
          <Box>
            <Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
              模型评估节点用于评估机器学习模型的性能指标。将此节点连接到机器学习模型节点后，执行节点获取评估结果。
            </Typography>

            {/* 显示已有的评估指标（如果存在） */}
            {hasMetrics && metrics ? (
              <Box sx={{ mt: 2, mb: 2 }}>
                <Typography variant="subtitle2" gutterBottom>
                  评估指标
                </Typography>
                <Paper variant="outlined" sx={{ p: 2 }}>
                  <Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 1 }}>
                    <Typography variant="body2">准确率:</Typography>
                    <Typography variant="body2" fontWeight="bold">
                      {(metrics.accuracy * 100).toFixed(2)}%
                    </Typography>
                  </Box>
                  <Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 1 }}>
                    <Typography variant="body2">精确率:</Typography>
                    <Typography variant="body2" fontWeight="bold">
                      {(metrics.precision * 100).toFixed(2)}%
                    </Typography>
                  </Box>
                  <Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 1 }}>
                    <Typography variant="body2">召回率:</Typography>
                    <Typography variant="body2" fontWeight="bold">
                      {(metrics.recall * 100).toFixed(2)}%
                    </Typography>
                  </Box>
                  <Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 1 }}>
                    <Typography variant="body2">F1分数:</Typography>
                    <Typography variant="body2" fontWeight="bold">
                      {(metrics.f1 * 100).toFixed(2)}%
                    </Typography>
                  </Box>
                </Paper>
              </Box>
            ) : (
              <Box sx={{ mt: 2, p: 2, bgcolor: '#f5f5f5', borderRadius: 1, textAlign: 'center' }}>
                <Typography variant="body2" color="text.secondary">
                  尚未获取评估结果。请连接到机器学习模型节点并执行。
                </Typography>
              </Box>
            )}
          </Box>
        );
      };

      return (
        <Box sx={{ mt: 2 }}>
          <Typography variant="subtitle2" gutterBottom>
            可视化设置
          </Typography>
          
          {node.data.type === 'model_evaluation' ? (
            renderModelEvaluationParams()
          ) : (
          <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
            {node.data.type === 'structured_view' && (
              <TextField
                label="每页行数"
                type="number"
                value={params.page_size || 50} // 修改默认值为 50
                onChange={(e) => handleParamChange('page_size', Number(e.target.value))}
                size="small"
                fullWidth
              />
            )}
            
              {(['bar_chart', 'line_chart', 'scatter_plot'].includes(node.data.type)) && (
              <>
                <TextField
                  label="X轴列"
                  value={params.x_column || ''}
                  onChange={(e) => handleParamChange('x_column', e.target.value)}
                  size="small"
                  fullWidth
                />
                <TextField
                  label="Y轴列"
                  value={params.y_column || ''}
                  onChange={(e) => handleParamChange('y_column', e.target.value)}
                  size="small"
                  fullWidth
                />
              </>
            )}
  
              {(node.data.type === 'pie_chart') && (
              <TextField
                label="值列"
                value={params.value_column || ''}
                onChange={(e) => handleParamChange('value_column', e.target.value)}
                size="small"
                fullWidth
              />
            )}
  
              {(node.data.type === 'heatmap') && (
              <TextField
                label="相关性列"
                value={params.correlation_columns || ''}
                onChange={(e) => handleParamChange('correlation_columns', e.target.value)}
                size="small"
                fullWidth
                helperText="输入要计算相关性的列名，多个列用逗号分隔"
              />
            )}
          </Box>
          )}
        </Box>
      );
    };

    // 特征选择结果预览 - 类型安全版本
    const renderFeatureSelectionResults = () => {
      if (!node.data.lastExecutionResult || typeof node.data.lastExecutionResult !== 'object') {
        return null;
      }

      // 检查是否存在已定义的特征选择结果
      const result = node.data.lastExecutionResult;
      const hasSelectedFeatures = 'selected_features' in result && 
                                  Array.isArray(result.selected_features);
      
      if (!hasSelectedFeatures) {
        return null;
      }

      // 获取特征相关信息
      const selectedFeatures = result.selected_features as string[];
      const originalFeatures = 'original_features' in result && Array.isArray(result.original_features) 
        ? result.original_features as string[] 
        : [];
      
      const hasFeatureScores = 'feature_scores' in result && 
                               result.feature_scores && 
                               typeof result.feature_scores === 'object';

      const selectionRate = originalFeatures.length 
        ? (selectedFeatures.length / originalFeatures.length * 100).toFixed(1) 
        : '0.0';

      return (
        <Box sx={{ mt: 2 }}>
          <Typography variant="subtitle2" gutterBottom>
            特征选择结果
          </Typography>
          <Paper variant="outlined" sx={{ p: 2 }}>
            <Typography variant="body2" gutterBottom>
              原始特征数量: {originalFeatures.length || '未知'}
            </Typography>
            <Typography variant="body2" gutterBottom>
              选择后特征数量: {selectedFeatures.length}
            </Typography>
            <Typography variant="body2" color="text.secondary">
              选择率: {selectionRate}%
            </Typography>
            
            {/* 特征得分预览（仅显示前5个） */}
            {hasFeatureScores && (
              <Box sx={{ mt: 2 }}>
                <Typography variant="caption" gutterBottom>
                  特征得分:
                </Typography>
                <TableContainer sx={{ maxHeight: 200 }}>
                  <Table size="small">
                    <TableHead>
                      <TableRow>
                        <TableCell>特征名</TableCell>
                        <TableCell align="right">得分</TableCell>
                      </TableRow>
                    </TableHead>
                    <TableBody>
                      {Object.entries(result.feature_scores as Record<string, number>)
                        .sort((a, b) => b[1] - a[1])
                        .slice(0, 5)
                        .map(([feature, score]) => (
                          <TableRow key={feature}>
                            <TableCell>{feature}</TableCell>
                            <TableCell align="right">
                              {typeof score === 'number' ? score.toFixed(4) : String(score)}
                            </TableCell>
                          </TableRow>
                        ))}
                    </TableBody>
                  </Table>
                </TableContainer>
              </Box>
            )}
          </Paper>
        </Box>
      );
    };

    // 添加特征选择节点参数渲染函数
    const renderFeatureSelectionParams = () => {
      if (node.data.type !== 'feature_selection_filter') {
        return null;
      }

      // 获取选择方法
      const method = node.data.params?.feature_selection_method || 'variance';
      
      // 获取上游数据和列信息
      const upstreamData = getUpstreamData();
      const availableColumns = upstreamData.columns || [];

      return (
        <Box sx={{ mt: 2 }}>
          <Typography variant="subtitle2" gutterBottom>
            特征选择设置
          </Typography>
          <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
            <FormControl size="small" fullWidth>
              <InputLabel>选择方法</InputLabel>
              <Select
                value={method}
                label="选择方法"
                onChange={(e) => handleParamChange('feature_selection_method', e.target.value)}
              >
                <MenuItem value="variance">方差过滤</MenuItem>
                <MenuItem value="correlation">特征间相关性过滤</MenuItem>
                <MenuItem value="target_correlation">目标相关性过滤</MenuItem>
                <MenuItem value="chi2">卡方检验</MenuItem>
                <MenuItem value="f_test">F检验</MenuItem>
                <MenuItem value="mutual_info">互信息</MenuItem>
                <MenuItem value="information_gain">信息增益</MenuItem>
                <MenuItem value="relief">Relief算法</MenuItem>
              </Select>
              <FormHelperText>
                {method === 'variance' 
                  ? '方差过滤：移除低方差特征'
                  : method === 'correlation' 
                  ? '特征间相关性过滤：移除互相高度相关的特征'
                  : method === 'target_correlation'
                  ? '目标相关性过滤：保留与目标变量高度相关的特征'
                  : method === 'chi2' 
                  ? '卡方检验：基于与目标变量的相关性选择特征'
                  : method === 'f_test' 
                  ? 'F检验：基于F统计量选择特征'
                  : method === 'information_gain'
                  ? '信息增益：基于特征对目标变量的信息量选择特征'
                  : method === 'relief'
                  ? 'Relief算法：基于实例间距离评估特征'
                  : '互信息：基于互信息选择特征'}
              </FormHelperText>
            </FormControl>

            {/* 根据方法显示不同参数 */}
            {method === 'variance' && (
              <TextField
                label="方差阈值"
                type="number"
                value={node.data.params?.variance_threshold || 0}
                onChange={(e) => handleParamChange('variance_threshold', parseFloat(e.target.value))}
                size="small"
                fullWidth
                inputProps={{ step: 0.01, min: 0 }}
                helperText="方差低于此阈值的特征将被移除"
              />
            )}
            
            {method === 'correlation' && (
              <TextField
                label="相关性阈值"
                type="number"
                value={node.data.params?.correlation_threshold || 0.9}
                onChange={(e) => handleParamChange('correlation_threshold', parseFloat(e.target.value))}
                size="small"
                fullWidth
                inputProps={{ step: 0.01, min: 0, max: 1 }}
                helperText="相关性高于此阈值的特征对将被移除一个"
              />
            )}
            
            {method === 'target_correlation' && (
              <>
                {/* 目标列选择 */}
                <Box sx={{ mb: 2 }}>
                  <TextField
                    fullWidth
                    label="目标列"
                    value={node.data.params?.target_column || ''}
                    onChange={(e) => handleParamChange('target_column', e.target.value)}
                    InputProps={{
                      endAdornment: (
                        <IconButton onClick={() => handleOpenColumnDialog('target')}>
                          <AddIcon />
                        </IconButton>
                      ),
                    }}
                  />
                  <FormHelperText>
                    选择要与特征计算相关性的目标列
                  </FormHelperText>
                </Box>
                
                {/* 相关性方式选择 */}
                <FormControl size="small" fullWidth>
                  <InputLabel>选择方式</InputLabel>
                  <Select
                    value={node.data.params?.selection_mode || 'threshold'}
                    label="选择方式"
                    onChange={(e) => handleParamChange('selection_mode', e.target.value)}
                  >
                    <MenuItem value="threshold">按相关性阈值</MenuItem>
                    <MenuItem value="k_best">选择前K个特征</MenuItem>
                  </Select>
                </FormControl>
                
                {/* 根据选择方式显示不同参数 */}
                {(!node.data.params?.selection_mode || node.data.params?.selection_mode === 'threshold') ? (
                  <TextField
                    label="相关性阈值"
                    type="number"
                    value={node.data.params?.threshold || 0.1}
                    onChange={(e) => handleParamChange('threshold', parseFloat(e.target.value))}
                    size="small"
                    fullWidth
                    inputProps={{ step: 0.01, min: 0, max: 1 }}
                    helperText="保留与目标相关性高于此阈值的特征"
                  />
                ) : (
                  <TextField
                    label="选择特征数量"
                    type="number"
                    value={node.data.params?.k || 10}
                    onChange={(e) => handleParamChange('k', parseInt(e.target.value, 10))}
                    size="small"
                    fullWidth
                    inputProps={{ min: 1 }}
                    helperText="选择与目标相关性最高的K个特征"
                  />
                )}
              </>
            )}
            
            {(method === 'chi2' || method === 'f_test' || method === 'mutual_info' || method === 'information_gain') && (
              <>
                <TextField
                  label="选择特征数量"
                  type="number"
                  value={node.data.params?.k_best || 10}
                  onChange={(e) => handleParamChange('k_best', parseInt(e.target.value, 10))}
                  size="small"
                  fullWidth
                  inputProps={{ min: 1 }}
                  helperText="选择得分最高的K个特征"
                />
                
                {/* 目标列选择 */}
                <Box sx={{ mb: 2 }}>
                  <TextField
                    fullWidth
                    label="目标列"
                    value={node.data.params?.target_column || ''}
                    onChange={(e) => handleParamChange('target_column', e.target.value)}
                    InputProps={{
                      endAdornment: (
                        <IconButton onClick={() => handleOpenColumnDialog('target')}>
                          <AddIcon />
                        </IconButton>
                      ),
                    }}
                  />
                  <FormHelperText>
                    输入目标列名称，或点击按钮从列表中选择（用于监督学习特征选择方法）
                  </FormHelperText>
                </Box>
              </>
            )}
            
            {method === 'relief' && (
              <>
                <TextField
                  label="选择特征数量"
                  type="number"
                  value={node.data.params?.k_best || 10}
                  onChange={(e) => handleParamChange('k_best', parseInt(e.target.value, 10))}
                  size="small"
                  fullWidth
                  inputProps={{ min: 1 }}
                  helperText="选择得分最高的K个特征"
                />
                
                <TextField
                  label="采样数量"
                  type="number"
                  value={node.data.params?.sample_size || ''}
                  onChange={(e) => handleParamChange('sample_size', parseInt(e.target.value, 10))}
                  size="small"
                  fullWidth
                  inputProps={{ min: 1 }}
                  helperText="用于计算Relief评分的样本数量（默认为数据集大小的10%，但不少于10个、不多于100个）"
                />
                
                {/* 目标列选择 */}
                <Box sx={{ mb: 2 }}>
                  <TextField
                    fullWidth
                    label="目标列"
                    value={node.data.params?.target_column || ''}
                    onChange={(e) => handleParamChange('target_column', e.target.value)}
                    InputProps={{
                      endAdornment: (
                        <IconButton onClick={() => handleOpenColumnDialog('target')}>
                          <AddIcon />
                        </IconButton>
                      ),
                    }}
                  />
                  <FormHelperText>
                    输入目标列名称，Relief算法需要目标列来评估特征重要性
                  </FormHelperText>
                </Box>
              </>
            )}
            
            {/* 特征选择结果预览 */}
            {renderFeatureSelectionResults()}
          </Box>
        </Box>
      );
    };

    // 渲染通用参数
    const renderCommonParams = () => {
      return (
        <Box sx={{ mt: 2 }}>
          <Typography variant="subtitle2" gutterBottom>
            基本设置
          </Typography>
          <TextField
            label="节点名称"
            value={label || ''}
            onChange={(e) => handleLabelChange(e.target.value)}
            size="small"
            fullWidth
            sx={{ mb: 2 }}
          />
        </Box>
      );
    };

    // 明确返回React节点
    return (
      <Box sx={{ p: 2, maxHeight: '100vh', overflowY: 'auto' }}>
        <Typography variant="h6" gutterBottom>
          节点属性
        </Typography>
        
        {renderCommonParams()}
        {renderDataInputParams()}
        {renderDataProcessingParams()}
        {renderFeatureSelectionParams()}
        {renderMachineLearningParams()}
        {renderVisualizationParams()}
        
        <Box sx={{ mt: 2, display: 'flex', flexDirection: 'column', gap: 1 }}>
          <Button
            variant="contained"
            color="primary"
            onClick={handleExecute}
            disabled={isLoading || (
              node.data.type === 'structured_view' || node.data.type === 'model_evaluation' ? false :
              node.data.type === 'logistic_regression' || node.data.type === 'random_forest' || node.data.type === 'svm' ? 
                !node.data.params?.target_column || !node.data.params?.feature_columns?.length :
              node.data.type === 'feature_selection_filter' ?
                (node.data.params?.feature_selection_method === 'chi2' || 
                 node.data.params?.feature_selection_method === 'f_test' || 
                 node.data.params?.feature_selection_method === 'mutual_info') && 
                 !node.data.params?.target_column :
              !node.data.params?.file
            )}
            fullWidth
          >
            {isLoading ? '执行中...' : '执行节点'}
          </Button>
          <Button
            variant="outlined"
            color="error"
            onClick={() => {
              if (window.confirm('确定要删除此节点吗？')) {
                onDelete(node.id);
              }
            }}
            fullWidth
            startIcon={<DeleteIcon />}
          >
            删除节点
          </Button>
        </Box>
        {success && (
          <Alert 
            severity="success" 
            sx={{ 
              mt: 2,
              mb: 2,
              '& .MuiAlert-message': {
                wordBreak: 'break-word',
              },
              border: '1px solid #4caf50',
              borderRadius: '4px',
              boxShadow: '0 2px 4px rgba(0,0,0,0.1)'
            }}
          >
            <Typography variant="subtitle2" gutterBottom>操作成功</Typography>
            <Typography variant="body2">{success}</Typography>
            {success.includes('部分预览') && (
              <Box mt={1}>
                <Typography variant="caption" color="text.secondary">
                  注意：由于数据量较大，系统仅加载了部分数据用于预览。完整数据将在处理过程中使用。
                </Typography>
              </Box>
            )}
          </Alert>
        )}
        {error && (
          <Alert 
            severity="error" 
            sx={{ 
              mt: 2, 
              mb: 2,
              '& .MuiAlert-message': {
                wordBreak: 'break-word',
                whiteSpace: 'pre-wrap',
                fontFamily: 'inherit'
              },
              border: '1px solid #f44336',
              borderRadius: '4px',
              boxShadow: '0 2px 4px rgba(0,0,0,0.1)'
            }}
          >
            <Typography variant="subtitle2" gutterBottom>文件上传出错</Typography>
            <Typography variant="body2">{error}</Typography>
            {error.includes('数据格式') || error.includes('数据类型') ? (
              <Box mt={1}>
                <Typography variant="caption" color="text.secondary">
                  建议：尝试在Excel中清理数据，移除特殊格式，或将内容另存为CSV格式后再上传。
                </Typography>
              </Box>
            ) : null}
          </Alert>
        )}
        
        {/* 确保在所有节点类型中都渲染列选择对话框 */}
        {renderColumnSelectionDialog()}
      </Box>
    );
  };

  export default PropertiesPanel;